package template

const (
	signProjectNp        = "{namespace}"
	signProjectName      = "{service_name}"
	signProjectNameProto = "{service_name_proto}"
)

const (
	templateStartupVars = `package startup

import (
	
)

// SetupVars 加载变量
func SetupVars() error {
	var err error
	// 本应用自己全局变量
	return err
}

func StopFunc() error {
	var err error
	// 当kelvins收到退出信号时将会调用
	// 本应用的资源回收通常在这里进行，kelvins自动加载的资源回收由框架进行
	return err
}
`

	templatePkgUtilClient = `package util

import (
	"context"
	"gitee.com/kelvins-io/kelvins/config/setting"
	"gitee.com/kelvins-io/kelvins/util/client_conn"
	"gitee.com/kelvins-io/kelvins/util/middleware"
	"google.golang.org/grpc"
)

func GetGrpcClient(ctx context.Context, serverName string) (*grpc.ClientConn, error) {
	client, err := client_conn.NewConnClient(serverName)
	if err != nil {
		return nil, err
	}
	// 调用其它RPC填写OAUTH信息
	// 应该根据serverName去加载对应的token（如果需要的话），这里只是为了方便将所有服务的token设为一样
	conf := &setting.RPCAuthSettingS{
		Token:             "c9VW6ForlmzdeDkZE2i8", // 如果对方服务不需要授权，则token置空
		TransportSecurity: false,
	}
	opts := middleware.GetRPCAuthDialOptions(conf)
	return client.GetConn(ctx, opts...)
}

func GetHttpEndpoints(ctx context.Context,serverName string) ([]string, error) {
	client, err := client_conn.NewConnClient(serverName)
	if err != nil {
		return nil, err
	}
	return client.GetEndpoints(ctx)
}`
	templatePkgUtilEmailHelper = `package email

import (
	"context"
	"gitee.com/kelvins-io/kelvins"
	"{namespace}/{service_name}/vars"
	"strings"
	"sync"
	"time"
)

var (
	one                sync.Once
	DefaultEmailHelper *Client
)

func initVars() {
	DefaultEmailHelper = NewClient(vars.EmailConfigSetting.User,vars.EmailConfigSetting.Password,vars.EmailConfigSetting.Host,vars.EmailConfigSetting.Port) // 初始邮件客户端，请传入参数
}

const maxRetrySendTimes = 3
const retryIdleTime = 500 * time.Millisecond

func SendEmailNotice(ctx context.Context, receivers, subject, msg string) error {
	one.Do(func() {
		initVars()
	})
	var err error
	emailReq := &SendRequest{
		Receivers: strings.Split(receivers, ","),
		Subject:   subject,
		Message:   msg,
	}

	// retry send email
	for retryCount := 0; retryCount < maxRetrySendTimes; retryCount++ {
		err = DefaultEmailHelper.SendEmail(emailReq)
		if err == nil {
			break
		}
		time.Sleep(retryIdleTime)
	}

	if err != nil {
		kelvins.ErrLogger.Errorf(ctx, "send email err: %v, req: %v", err, emailReq)
		return err
	}

	return nil
}
`
	templatePkgUtilEmail = `package email

import (
	"context"
	"crypto/tls"
	"fmt"
	"gitee.com/kelvins-io/kelvins"
	"net/smtp"
	"strings"
)

type SendRequest struct {
	Receivers []string
	Subject   string
	Message   string
}

type Config struct {
	User     string
	Password string
	Host     string
	Port     string
}

type Client struct {
	config *Config
}

func NewClient(user, pwd, host, port string) *Client {
	return &Client{config: &Config{
		User:     user,
		Password: pwd,
		Host:     host,
		Port:     port,
	}}
}

func (e *Client) buildMessage(req *SendRequest) string {
	var buf strings.Builder
	buf.WriteString(fmt.Sprintf("From: 来自远方的问候<%s>\r\n", e.config.User))
	if len(req.Receivers) > 0 {
		buf.WriteString(fmt.Sprintf("To: %s\r\n", strings.Join(req.Receivers, ";")))
	}
	buf.WriteString(fmt.Sprintf("Subject: %s\r\n", req.Subject))
	buf.WriteString("Content-Type: text/html; charset=UTF-8")
	buf.WriteString("\r\n\r\n")
	buf.WriteString(req.Message)

	return buf.String()
}

func (e *Client) SendEmail(req *SendRequest) error {

	messageBody := e.buildMessage(req)
	//build an auth
	auth := smtp.PlainAuth("", e.config.User, e.config.Password, e.config.Host)

	tlsConfig := &tls.Config{
		InsecureSkipVerify: false,
		ServerName:         e.config.Host,
	}
	serverName := e.config.Host + ":" + e.config.Port

	conn, err := tls.Dial("tcp", serverName, tlsConfig)
	if err != nil {
		return err
	}

	client, err := smtp.NewClient(conn, e.config.Host)
	if err != nil {
		return err
	}

	// step 1: Use Auth
	if err = client.Auth(auth); err != nil {
		return err
	}

	// step 2: add all from and to
	if err = client.Mail(e.config.User); err != nil {
		return err
	}
	for _, k := range req.Receivers {
		if err = client.Rcpt(k); err != nil {
			return err
		}
	}

	w, err := client.Data()
	if err != nil {
		return err
	}

	_, err = w.Write([]byte(messageBody))
	if err != nil {
		return err
	}

	err = w.Close()
	if err != nil {
		return err
	}

	err = client.Quit()
	if err != nil {
		kelvins.ErrLogger.Errorf(context.Background(), "client quit err: %v", err)
		return err
	}

	return nil
}
`

	templatePkgCode = `package code

import "gitee.com/kelvins-io/common/errcode"

const (
	Success     = 29999999
	ErrorServer = 29999998
)

var ErrMap = make(map[int]string)

func init() {
	dict := map[int]string{
		Success:                    "OK",
		ErrorServer:                "服务器错误",
	}
	errcode.RegisterErrMsgDict(dict)
	for key, _ := range dict {
		ErrMap[key] = dict[key]
	}
}
`
	templateModelMysqlTable = `package mysql

const (
	TableXXX_NAME             = "{service_name}"
)

// 将xorm或gorm反射过来的struct粘贴到这里
type TableXXX struct {
	ID int 
}
`
	templateModelArgsConst = `package args

// 其它RPC服务，如果调用请确保DNS可以根据服务名找到服务IP地址
const (
	RpcServiceXXX  = "{service_name}"
)`

	templateDockerFile = `FROM golang:1.13.15-buster as gobuild
WORKDIR $GOPATH/src/{namespace}/{service_name}
COPY . .
ENV GOPROXY=https://goproxy.io,direct
RUN bash ./build.sh
# FROM alpine:latest as gorun
FROM ubuntu:latest as gorun
WORKDIR /www/
COPY --from=gobuild /go/src/{namespace}/{service_name}/{service_name} .
COPY --from=gobuild /go/src/{namespace}/{service_name}/etc ./etc
CMD ["./{service_name}"]
`
	templateBuildShell = `echo 当前分支
git branch

echo 拉取依赖
go mod vendor

cp -n ./etc/app.ini.example ./etc/app.ini

echo 开始构建版本
go build -o {service_name} main.go`

	templateBuildRunShell = `echo 当前分支
git branch

echo 拉取依赖
go mod vendor

echo 开始构建
go build -o {service_name} main.go

cp -n ./etc/app.ini.example ./etc/app.ini

echo 开始运行{service_name}
nohup ./{service_name} -s start >nohup.out  2>&1  &`

	templateCleanBinShell = `#! /bin/bash
rm -rf ./{service_name}`

	templateCleanLogsShell = `#! /bin/bash
rm -rf logs/
rm -rf nohup.out`

	templateGenPbPy = `#!/usr/bin/etc python3
# -*- coding:utf-8 -*-

import os
import sys
# py3 commands模块并入了subprocess
try:
    import commands
except ImportError:
    import subprocess as commands

project_name = os.path.basename(os.path.abspath("."))


def genpb(proto_arr):
    '''复制proto文件到工程的proto文件夹下，且执行.go, .pb, swagger.json的生成'''
    proto_pkg_path = get_proto_pkg_path()
    if not os.path.exists("./proto"):
        os.mkdir("./proto")
    for proto_dir in proto_arr:
        gen_proto(proto_pkg_path, proto_dir)
    # 在./proto目录下生成swagger.json.go
    if os.system(r'''go-bindata -ignore=\\.go -ignore=\\.proto -ignore=\\.md -o=./proto/swagger_json.go -pkg=proto ./proto/...''') != 0: # 防止转义，原始字符串
        print("GO_BINDATA ./proto/swagger.json.go ERROR!")
        sys.exit(1)


def gen_proto(proto_pkg_path, proto_dir):
    '''复制proto文件夹到工程的proto文件夹下,并生成相应的go文件'''
    # proto文件夹在工程下对应的文件夹名
    sub_dir = os.path.basename(os.path.abspath(proto_dir)).replace("-", "_")
    # proto文件夹在当前项目目录下的相对目录
    rel_pro_dir = "./proto/" + sub_dir
    # 如果文件夹不存在就创建
    if not os.path.exists(rel_pro_dir):
        os.system("mkdir %s" % rel_pro_dir)
    # 删除文件夹下所有文件
    os.system("rm -rf %s/*" % rel_pro_dir)
    # 将proto_dir下的所有文件复制到相应的地方
    os.system("cp -r %s/* %s" % (proto_dir, rel_pro_dir))
    # 获取rel_pro_dir下所有的子目录
    status, result = commands.getstatusoutput("find %s -type d" % rel_pro_dir)
    if status != 0:
        print(result)
        sys.exit(1)
    dirs = result.split("\n")
    for d in dirs:
        status, result = commands.getstatusoutput(
            "ls %s/*.proto 2>/dev/null | wc -l" % d)
        if status != 0:
            print(result)
            sys.exit(1)
        if result.strip() == "0":
            continue
        if os.system("protoc -I. -I%s --go_out=plugins=grpc:. %s/*.proto" % (proto_pkg_path, d)) != 0:
            print("PROTOC PB ERROR!!!")
            sys.exit(1)
        if os.system("protoc -I. -I%s --grpc-gateway_out=logtostderr=true:. %s/*.proto" % (proto_pkg_path, d)) != 0:
            print("PTOTOC PB.GW ERROR!!!")
            sys.exit(1)
        # 如果是项目对应的proto目录，则需要生成swagger文件
        if sub_dir == project_name.replace("-", "_") + "_proto":
            if os.system("protoc -I. -I%s --swagger_out=logtostderr=true:. %s/*.proto" % (proto_pkg_path, d)) != 0:
                print("PTOTOC SWAGGER ERROR!!!")
                sys.exit(1)


def get_proto_pkg_path():
    '''获取包含proto相关所有包的目录，优先使用vendor目录，然后使用gopath'''
    vendor = os.path.abspath("./vendor")
    if check_proto_pkg(vendor):
        return vendor
    gopath = os.environ.get("GOPATH")
    if gopath is None:
        print("未定义GOPATH环境变量")
        sys.exit(1)
    # gopath 可能有多个，unix以":"分隔，windows以";"分隔
    for path in gopath.split(":"):
        proto_pkg = path + "/src"
        if check_proto_pkg(proto_pkg):
            return proto_pkg
    print("在vendor下面和GOPATH下面都找不到proto相关目录")
    sys.exit(1)


def check_proto_pkg(base_dir):
    '''检查proto相关的目录是否都存在'''
    rel_paths = [
        "/gitee.com/kelvins-io/common/proto",
        "/gitee.com/kelvins-io/common/proto/common",
        "/gitee.com/kelvins-io/common/proto/google/api",
    ]
    for rel_path in rel_paths:
        if not os.path.exists(base_dir + rel_path):
            return False
    return True


if __name__ == "__main__":
    proto_arr = sys.argv[1:]
    if len(proto_arr) > 0:
        genpb(proto_arr)
`

	templateXormReveRseYaml = `kind: reverse
name: mydb
source:
  database: mysql
  conn_str: 'MYSQL_USER:MYSQL_PASSWORD@tcp(MYSQL_HOST:MYSQL_PORT)/{service_name}?charset=utf8'
targets:
  - type: codes
    language: golang
    output_dir: ./`

	templateRestartShell = `#! /bin/bash
./{service_name} -s restart
`
	templateStartShell = `#! /bin/bash
nohup ./{service_name} -s start >nohup.out  2>&1  &
`
	templateStopShell = `#! /bin/bash
./{service_name} -s stop`
)
